home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / pyshared / PIL / TiffImagePlugin.py < prev    next >
Text File  |  2008-01-28  |  24KB  |  770 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: TiffImagePlugin.py 2803 2006-07-31 19:18:57Z fredrik $
  4. #
  5. # TIFF file handling
  6. #
  7. # TIFF is a flexible, if somewhat aged, image file format originally
  8. # defined by Aldus.  Although TIFF supports a wide variety of pixel
  9. # layouts and compression methods, the name doesn't really stand for
  10. # "thousands of incompatible file formats," it just feels that way.
  11. #
  12. # To read TIFF data from a stream, the stream must be seekable.  For
  13. # progressive decoding, make sure to use TIFF files where the tag
  14. # directory is placed first in the file.
  15. #
  16. # History:
  17. # 1995-09-01 fl   Created
  18. # 1996-05-04 fl   Handle JPEGTABLES tag
  19. # 1996-05-18 fl   Fixed COLORMAP support
  20. # 1997-01-05 fl   Fixed PREDICTOR support
  21. # 1997-08-27 fl   Added support for rational tags (from Perry Stoll)
  22. # 1998-01-10 fl   Fixed seek/tell (from Jan Blom)
  23. # 1998-07-15 fl   Use private names for internal variables
  24. # 1999-06-13 fl   Rewritten for PIL 1.0 (1.0)
  25. # 2000-10-11 fl   Additional fixes for Python 2.0 (1.1)
  26. # 2001-04-17 fl   Fixed rewind support (seek to frame 0) (1.2)
  27. # 2001-05-12 fl   Added write support for more tags (from Greg Couch) (1.3)
  28. # 2001-12-18 fl   Added workaround for broken Matrox library
  29. # 2002-01-18 fl   Don't mess up if photometric tag is missing (D. Alan Stewart)
  30. # 2003-05-19 fl   Check FILLORDER tag
  31. # 2003-09-26 fl   Added RGBa support
  32. # 2004-02-24 fl   Added DPI support; fixed rational write support
  33. # 2005-02-07 fl   Added workaround for broken Corel Draw 10 files
  34. # 2006-01-09 fl   Added support for float/double tags (from Russell Nelson)
  35. #
  36. # Copyright (c) 1997-2006 by Secret Labs AB.  All rights reserved.
  37. # Copyright (c) 1995-1997 by Fredrik Lundh
  38. #
  39. # See the README file for information on usage and redistribution.
  40. #
  41.  
  42. __version__ = "1.3.5"
  43.  
  44. import Image, ImageFile
  45. import ImagePalette
  46.  
  47. import array, string, sys
  48.  
  49. try:
  50.     if sys.byteorder == "little":
  51.         byteorder = "II"
  52.     else:
  53.         byteorder = "MM"
  54. except AttributeError:
  55.     if ord(array.array("i",[1]).tostring()[0]):
  56.         byteorder = "II"
  57.     else:
  58.         byteorder = "MM"
  59.  
  60. #
  61. # --------------------------------------------------------------------
  62. # Read TIFF files
  63.  
  64. def il16(c,o=0):
  65.     return ord(c[o]) + (ord(c[o+1])<<8)
  66. def il32(c,o=0):
  67.     return ord(c[o]) + (ord(c[o+1])<<8) + (ord(c[o+2])<<16) + (ord(c[o+3])<<24)
  68. def ol16(i):
  69.     return chr(i&255) + chr(i>>8&255)
  70. def ol32(i):
  71.     return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
  72.  
  73. def ib16(c,o=0):
  74.     return ord(c[o+1]) + (ord(c[o])<<8)
  75. def ib32(c,o=0):
  76.     return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24)
  77.  
  78. # a few tag names, just to make the code below a bit more readable
  79. IMAGEWIDTH = 256
  80. IMAGELENGTH = 257
  81. BITSPERSAMPLE = 258
  82. COMPRESSION = 259
  83. PHOTOMETRIC_INTERPRETATION = 262
  84. FILLORDER = 266
  85. IMAGEDESCRIPTION = 270
  86. STRIPOFFSETS = 273
  87. SAMPLESPERPIXEL = 277
  88. ROWSPERSTRIP = 278
  89. STRIPBYTECOUNTS = 279
  90. X_RESOLUTION = 282
  91. Y_RESOLUTION = 283
  92. PLANAR_CONFIGURATION = 284
  93. RESOLUTION_UNIT = 296
  94. SOFTWARE = 305
  95. DATE_TIME = 306
  96. ARTIST = 315
  97. PREDICTOR = 317
  98. COLORMAP = 320
  99. EXTRASAMPLES = 338
  100. SAMPLEFORMAT = 339
  101. JPEGTABLES = 347
  102. COPYRIGHT = 33432
  103. IPTC_NAA_CHUNK = 33723 # newsphoto properties
  104. PHOTOSHOP_CHUNK = 34377 # photoshop properties
  105.  
  106. COMPRESSION_INFO = {
  107.     # Compression => pil compression name
  108.     1: "raw",
  109.     2: "tiff_ccitt",
  110.     3: "group3",
  111.     4: "group4",
  112.     5: "tiff_lzw",
  113.     6: "tiff_jpeg", # obsolete
  114.     7: "jpeg",
  115.     32771: "tiff_raw_16", # 16-bit padding
  116.     32773: "packbits"
  117. }
  118.  
  119. OPEN_INFO = {
  120.     # (PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
  121.     #  ExtraSamples) => mode, rawmode
  122.     (0, 1, 1, (1,), ()): ("1", "1;I"),
  123.     (0, 1, 2, (1,), ()): ("1", "1;IR"),
  124.     (0, 1, 1, (8,), ()): ("L", "L;I"),
  125.     (0, 1, 2, (8,), ()): ("L", "L;IR"),
  126.     (1, 1, 1, (1,), ()): ("1", "1"),
  127.     (1, 1, 2, (1,), ()): ("1", "1;R"),
  128.     (1, 1, 1, (8,), ()): ("L", "L"),
  129.     (1, 1, 1, (8,8), (2,)): ("LA", "LA"),
  130.     (1, 1, 2, (8,), ()): ("L", "L;R"),
  131.     (1, 1, 1, (16,), ()): ("I;16", "I;16"),
  132.     (1, 2, 1, (16,), ()): ("I;16S", "I;16S"),
  133.     (1, 2, 1, (32,), ()): ("I", "I;32S"),
  134.     (1, 3, 1, (32,), ()): ("F", "F;32F"),
  135.     (2, 1, 1, (8,8,8), ()): ("RGB", "RGB"),
  136.     (2, 1, 2, (8,8,8), ()): ("RGB", "RGB;R"),
  137.     (2, 1, 1, (8,8,8,8), (0,)): ("RGBX", "RGBX"),
  138.     (2, 1, 1, (8,8,8,8), (1,)): ("RGBA", "RGBa"),
  139.     (2, 1, 1, (8,8,8,8), (2,)): ("RGBA", "RGBA"),
  140.     (2, 1, 1, (8,8,8,8), (999,)): ("RGBA", "RGBA"), # corel draw 10
  141.     (3, 1, 1, (1,), ()): ("P", "P;1"),
  142.     (3, 1, 2, (1,), ()): ("P", "P;1R"),
  143.     (3, 1, 1, (2,), ()): ("P", "P;2"),
  144.     (3, 1, 2, (2,), ()): ("P", "P;2R"),
  145.     (3, 1, 1, (4,), ()): ("P", "P;4"),
  146.     (3, 1, 2, (4,), ()): ("P", "P;4R"),
  147.     (3, 1, 1, (8,), ()): ("P", "P"),
  148.     (3, 1, 1, (8,8), (2,)): ("PA", "PA"),
  149.     (3, 1, 2, (8,), ()): ("P", "P;R"),
  150.     (5, 1, 1, (8,8,8,8), ()): ("CMYK", "CMYK"),
  151.     (6, 1, 1, (8,8,8), ()): ("YCbCr", "YCbCr"),
  152.     (8, 1, 1, (8,8,8), ()): ("LAB", "LAB"),
  153. }
  154.  
  155. PREFIXES = ["MM\000\052", "II\052\000", "II\xBC\000"]
  156.  
  157. def _accept(prefix):
  158.     return prefix[:4] in PREFIXES
  159.  
  160. ##
  161. # Wrapper for TIFF IFDs.
  162.  
  163. class ImageFileDirectory:
  164.  
  165.     # represents a TIFF tag directory.  to speed things up,
  166.     # we don't decode tags unless they're asked for.
  167.  
  168.     def __init__(self, prefix="II"):
  169.         self.prefix = prefix[:2]
  170.         if self.prefix == "MM":
  171.             self.i16, self.i32 = ib16, ib32
  172.             # FIXME: save doesn't yet support big-endian mode...
  173.         elif self.prefix == "II":
  174.             self.i16, self.i32 = il16, il32
  175.             self.o16, self.o32 = ol16, ol32
  176.         else:
  177.             raise SyntaxError("not a TIFF IFD")
  178.         self.reset()
  179.  
  180.     def reset(self):
  181.         self.tags = {}
  182.         self.tagdata = {}
  183.         self.next = None
  184.  
  185.     # dictionary API (sort of)
  186.  
  187.     def keys(self):
  188.         return self.tagdata.keys() + self.tags.keys()
  189.  
  190.     def items(self):
  191.         items = self.tags.items()
  192.         for tag in self.tagdata.keys():
  193.             items.append((tag, self[tag]))
  194.         return items
  195.  
  196.     def __len__(self):
  197.         return len(self.tagdata) + len(self.tags)
  198.  
  199.     def __getitem__(self, tag):
  200.         try:
  201.             return self.tags[tag]
  202.         except KeyError:
  203.             type, data = self.tagdata[tag] # unpack on the fly
  204.             size, handler = self.load_dispatch[type]
  205.             self.tags[tag] = data = handler(self, data)
  206.             del self.tagdata[tag]
  207.             return data
  208.  
  209.     def get(self, tag, default=None):
  210.         try:
  211.             return self[tag]
  212.         except KeyError:
  213.             return default
  214.  
  215.     def getscalar(self, tag, default=None):
  216.         try:
  217.             value = self[tag]
  218.             if len(value) != 1:
  219.                 if tag == SAMPLEFORMAT:
  220.                     # work around broken (?) matrox library
  221.                     # (from Ted Wright, via Bob Klimek)
  222.                     raise KeyError # use default
  223.                 raise ValueError, "not a scalar"
  224.             return value[0]
  225.         except KeyError:
  226.             if default is None:
  227.                 raise
  228.             return default
  229.  
  230.     def has_key(self, tag):
  231.         return self.tags.has_key(tag) or self.tagdata.has_key(tag)
  232.  
  233.     def __setitem__(self, tag, value):
  234.         if type(value) is not type(()):
  235.             value = (value,)
  236.         self.tags[tag] = value
  237.  
  238.     # load primitives
  239.  
  240.     load_dispatch = {}
  241.  
  242.     def load_byte(self, data):
  243.         l = []
  244.         for i in range(len(data)):
  245.             l.append(ord(data[i]))
  246.         return tuple(l)
  247.     load_dispatch[1] = (1, load_byte)
  248.  
  249.     def load_string(self, data):
  250.         if data[-1:] == '\0':
  251.             data = data[:-1]
  252.         return data
  253.     load_dispatch[2] = (1, load_string)
  254.  
  255.     def load_short(self, data):
  256.         l = []
  257.         for i in range(0, len(data), 2):
  258.             l.append(self.i16(data, i))
  259.         return tuple(l)
  260.     load_dispatch[3] = (2, load_short)
  261.  
  262.     def load_long(self, data):
  263.         l = []
  264.         for i in range(0, len(data), 4):
  265.             l.append(self.i32(data, i))
  266.         return tuple(l)
  267.     load_dispatch[4] = (4, load_long)
  268.  
  269.     def load_rational(self, data):
  270.         l = []
  271.         for i in range(0, len(data), 8):
  272.             l.append((self.i32(data, i), self.i32(data, i+4)))
  273.         return tuple(l)
  274.     load_dispatch[5] = (8, load_rational)
  275.  
  276.     def load_float(self, data):
  277.         a = array.array("f", data)
  278.         if self.prefix != byteorder:
  279.             a.byteswap()
  280.         return tuple(a)
  281.     load_dispatch[11] = (4, load_float)
  282.  
  283.     def load_double(self, data):
  284.         a = array.array("d", data)
  285.         if self.prefix != byteorder:
  286.             a.byteswap()
  287.         return tuple(a)
  288.     load_dispatch[12] = (8, load_double)
  289.  
  290.     def load_undefined(self, data):
  291.         # Untyped data
  292.         return data
  293.     load_dispatch[7] = (1, load_undefined)
  294.  
  295.     def load(self, fp):
  296.         # load tag dictionary
  297.  
  298.         self.reset()
  299.  
  300.         i16 = self.i16
  301.         i32 = self.i32
  302.  
  303.         for i in range(i16(fp.read(2))):
  304.  
  305.             ifd = fp.read(12)
  306.  
  307.             tag, typ = i16(ifd), i16(ifd, 2)
  308.  
  309.             if Image.DEBUG:
  310.                 import TiffTags
  311.                 tagname = TiffTags.TAGS.get(tag, "unknown")
  312.                 typname = TiffTags.TYPES.get(typ, "unknown")
  313.                 print "tag: %s (%d)" % (tagname, tag),
  314.                 print "- type: %s (%d)" % (typname, typ),
  315.  
  316.             try:
  317.                 dispatch = self.load_dispatch[typ]
  318.             except KeyError:
  319.                 if Image.DEBUG:
  320.                     print "- unsupported type", typ
  321.                 continue # ignore unsupported type
  322.  
  323.             size, handler = dispatch
  324.  
  325.             size = size * i32(ifd, 4)
  326.  
  327.             # Get and expand tag value
  328.             if size > 4:
  329.                 here = fp.tell()
  330.                 fp.seek(i32(ifd, 8))
  331.                 data = ImageFile._safe_read(fp, size)
  332.                 fp.seek(here)
  333.             else:
  334.                 data = ifd[8:8+size]
  335.  
  336.             if len(data) != size:
  337.                 raise IOError, "not enough data"
  338.  
  339.             self.tagdata[tag] = typ, data
  340.  
  341.             if Image.DEBUG:
  342.                 if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK):
  343.                     print "- value: <table: %d bytes>" % size
  344.                 else:
  345.                     print "- value:", self[tag]
  346.  
  347.         self.next = i32(fp.read(4))
  348.  
  349.     # save primitives
  350.  
  351.     def save(self, fp):
  352.  
  353.         o16 = self.o16
  354.         o32 = self.o32
  355.  
  356.         fp.write(o16(len(self.tags)))
  357.  
  358.         # always write in ascending tag order
  359.         tags = self.tags.items()
  360.         tags.sort()
  361.  
  362.         directory = []
  363.         append = directory.append
  364.  
  365.         offset = fp.tell() + len(self.tags) * 12 + 4
  366.  
  367.         stripoffsets = None
  368.  
  369.         # pass 1: convert tags to binary format
  370.         for tag, value in tags:
  371.  
  372.             if Image.DEBUG:
  373.                 import TiffTags
  374.                 tagname = TiffTags.TAGS.get(tag, "unknown")
  375.                 print "save: %s (%d)" % (tagname, tag),
  376.                 print "- value:", value
  377.  
  378.             if type(value[0]) is type(""):
  379.                 # string data
  380.                 typ = 2
  381.                 data = value = string.join(value, "\0") + "\0"
  382.  
  383.             else:
  384.                 # integer data
  385.                 if tag == STRIPOFFSETS:
  386.                     stripoffsets = len(directory)
  387.                     typ = 4 # to avoid catch-22
  388.                 elif tag in (X_RESOLUTION, Y_RESOLUTION):
  389.                     # identify rational data fields
  390.                     typ = 5
  391.                 else:
  392.                     typ = 3
  393.                     for v in value:
  394.                         if v >= 65536:
  395.                             typ = 4
  396.                 if typ == 3:
  397.                     data = string.join(map(o16, value), "")
  398.                 else:
  399.                     data = string.join(map(o32, value), "")
  400.  
  401.             # figure out if data fits into the directory
  402.             if len(data) == 4:
  403.                 append((tag, typ, len(value), data, ""))
  404.             elif len(data) < 4:
  405.                 append((tag, typ, len(value), data + (4-len(data))*"\0", ""))
  406.             else:
  407.                 count = len(value)
  408.                 if typ == 5:
  409.                     count = count / 2        # adjust for rational data field
  410.                 append((tag, typ, count, o32(offset), data))
  411.                 offset = offset + len(data)
  412.                 if offset & 1:
  413.                     offset = offset + 1 # word padding
  414.  
  415.         # update strip offset data to point beyond auxiliary data
  416.         if stripoffsets is not None:
  417.             tag, typ, count, value, data = directory[stripoffsets]
  418.             assert not data, "multistrip support not yet implemented"
  419.             value = o32(self.i32(value) + offset)
  420.             directory[stripoffsets] = tag, typ, count, value, data
  421.  
  422.         # pass 2: write directory to file
  423.         for tag, typ, count, value, data in directory:
  424.             if Image.DEBUG > 1:
  425.                 print tag, typ, count, repr(value), repr(data)
  426.             fp.write(o16(tag) + o16(typ) + o32(count) + value)
  427.         fp.write("\0\0\0\0") # end of directory
  428.  
  429.         # pass 3: write auxiliary data to file
  430.         for tag, typ, count, value, data in directory:
  431.             fp.write(data)
  432.             if len(data) & 1:
  433.                 fp.write("\0")
  434.  
  435.         return offset
  436.  
  437. ##
  438. # Image plugin for TIFF files.
  439.  
  440. class TiffImageFile(ImageFile.ImageFile):
  441.  
  442.     format = "TIFF"
  443.     format_description = "Adobe TIFF"
  444.  
  445.     def _open(self):
  446.         "Open the first image in a TIFF file"
  447.  
  448.         # Header
  449.         ifh = self.fp.read(8)
  450.  
  451.         if ifh[:4] not in PREFIXES:
  452.             raise SyntaxError, "not a TIFF file"
  453.  
  454.         # image file directory (tag dictionary)
  455.         self.tag = self.ifd = ImageFileDirectory(ifh[:2])
  456.  
  457.         # setup frame pointers
  458.         self.__first = self.__next = self.ifd.i32(ifh, 4)
  459.         self.__frame = -1
  460.         self.__fp = self.fp
  461.  
  462.         # and load the first frame
  463.         self._seek(0)
  464.  
  465.     def seek(self, frame):
  466.         "Select a given frame as current image"
  467.  
  468.         if frame < 0:
  469.             frame = 0
  470.         self._seek(frame)
  471.  
  472.     def tell(self):
  473.         "Return the current frame number"
  474.  
  475.         return self._tell()
  476.  
  477.     def _seek(self, frame):
  478.  
  479.         self.fp = self.__fp
  480.         if frame < self.__frame:
  481.             # rewind file
  482.             self.__frame = -1
  483.             self.__next = self.__first
  484.         while self.__frame < frame:
  485.             if not self.__next:
  486.                 raise EOFError, "no more images in TIFF file"
  487.             self.fp.seek(self.__next)
  488.             self.tag.load(self.fp)
  489.             self.__next = self.tag.next
  490.             self.__frame = self.__frame + 1
  491.         self._setup()
  492.  
  493.     def _tell(self):
  494.  
  495.         return self.__frame
  496.  
  497.     def _decoder(self, rawmode, layer):
  498.         "Setup decoder contexts"
  499.  
  500.         args = None
  501.         if rawmode == "RGB" and self._planar_configuration == 2:
  502.             rawmode = rawmode[layer]
  503.         compression = self._compression
  504.         if compression == "raw":
  505.             args = (rawmode, 0, 1)
  506.         elif compression == "jpeg":
  507.             args = rawmode, ""
  508.             if self.tag.has_key(JPEGTABLES):
  509.                 # Hack to handle abbreviated JPEG headers
  510.                 self.tile_prefix = self.tag[JPEGTABLES]
  511.         elif compression == "packbits":
  512.             args = rawmode
  513.         elif compression == "tiff_lzw":
  514.             args = rawmode
  515.             if self.tag.has_key(317):
  516.                 # Section 14: Differencing Predictor
  517.                 self.decoderconfig = (self.tag[PREDICTOR][0],)
  518.  
  519.         return args
  520.  
  521.     def _setup(self):
  522.         "Setup this image object based on current tags"
  523.  
  524.         if self.tag.has_key(0xBC01):
  525.             raise IOError, "Windows Media Photo files not yet supported"
  526.  
  527.         getscalar = self.tag.getscalar
  528.  
  529.         # extract relevant tags
  530.         self._compression = COMPRESSION_INFO[getscalar(COMPRESSION, 1)]
  531.         self._planar_configuration = getscalar(PLANAR_CONFIGURATION, 1)
  532.  
  533.         # photometric is a required tag, but not everyone is reading
  534.         # the specification
  535.         photo = getscalar(PHOTOMETRIC_INTERPRETATION, 0)
  536.  
  537.         fillorder = getscalar(FILLORDER, 1)
  538.  
  539.         if Image.DEBUG:
  540.             print "*** Summary ***"
  541.             print "- compression:", self._compression
  542.             print "- photometric_interpretation:", photo
  543.             print "- planar_configuration:", self._planar_configuration
  544.             print "- fill_order:", fillorder
  545.  
  546.         # size
  547.         xsize = getscalar(IMAGEWIDTH)
  548.         ysize = getscalar(IMAGELENGTH)
  549.         self.size = xsize, ysize
  550.  
  551.         if Image.DEBUG:
  552.             print "- size:", self.size
  553.  
  554.         format = getscalar(SAMPLEFORMAT, 1)
  555.  
  556.         # mode: check photometric interpretation and bits per pixel
  557.         key = (
  558.             photo, format, fillorder,
  559.             self.tag.get(BITSPERSAMPLE, (1,)),
  560.             self.tag.get(EXTRASAMPLES, ())
  561.             )
  562.         if Image.DEBUG:
  563.             print "format key:", key
  564.         try:
  565.             self.mode, rawmode = OPEN_INFO[key]
  566.         except KeyError:
  567.             if Image.DEBUG:
  568.                 print "- unsupported format"
  569.             raise SyntaxError, "unknown pixel mode"
  570.  
  571.         if Image.DEBUG:
  572.             print "- raw mode:", rawmode
  573.             print "- pil mode:", self.mode
  574.  
  575.         self.info["compression"] = self._compression
  576.  
  577.         xdpi = getscalar(X_RESOLUTION, (1, 1))
  578.         ydpi = getscalar(Y_RESOLUTION, (1, 1))
  579.  
  580.         if xdpi and ydpi:
  581.             xdpi = xdpi[0] / (xdpi[1] or 1)
  582.             ydpi = ydpi[0] / (ydpi[1] or 1)
  583.             unit = getscalar(RESOLUTION_UNIT, 1)
  584.             if unit == 1:
  585.                 self.info["aspect"] = xdpi, ydpi
  586.             elif unit == 2:
  587.                 self.info["dpi"] = xdpi, ydpi
  588.             elif unit == 3:
  589.                 self.info["dpi"] = (xdpi*.39370079, ydpi*.39370079)
  590.  
  591.         # build tile descriptors
  592.         x = y = l = 0
  593.         self.tile = []
  594.         if self.tag.has_key(STRIPOFFSETS):
  595.             # striped image
  596.             h = getscalar(ROWSPERSTRIP, ysize)
  597.             w = self.size[0]
  598.             a = None
  599.             for o in self.tag[STRIPOFFSETS]:
  600.                 if not a:
  601.                     a = self._decoder(rawmode, l)
  602.                 self.tile.append(
  603.                     (self._compression,
  604.                     (0, min(y, ysize), w, min(y+h, ysize)),
  605.                     o, a))
  606.                 y = y + h
  607.                 if y >= self.size[1]:
  608.                     x = y = 0
  609.                     l = l + 1
  610.                     a = None
  611.         elif self.tag.has_key(324):
  612.             # tiled image
  613.             w = getscalar(322)
  614.             h = getscalar(323)
  615.             a = None
  616.             for o in self.tag[324]:
  617.                 if not a:
  618.                     a = self._decoder(rawmode, l)
  619.                 # FIXME: this doesn't work if the image size
  620.                 # is not a multiple of the tile size...
  621.                 self.tile.append(
  622.                     (self._compression,
  623.                     (x, y, x+w, y+h),
  624.                     o, a))
  625.                 x = x + w
  626.                 if x >= self.size[0]:
  627.                     x, y = 0, y + h
  628.                     if y >= self.size[1]:
  629.                         x = y = 0
  630.                         l = l + 1
  631.                         a = None
  632.         else:
  633.             if Image.DEBUG:
  634.                 print "- unsupported data organization"
  635.             raise SyntaxError("unknown data organization")
  636.  
  637.         # fixup palette descriptor
  638.         if self.mode == "P":
  639.             palette = map(lambda a: chr(a / 256), self.tag[COLORMAP])
  640.             self.palette = ImagePalette.raw("RGB;L", string.join(palette, ""))
  641.  
  642. #
  643. # --------------------------------------------------------------------
  644. # Write TIFF files
  645.  
  646. # little endian is default
  647.  
  648. SAVE_INFO = {
  649.     # mode => rawmode, photometrics, sampleformat, bitspersample, extra
  650.     "1": ("1", 1, 1, (1,), None),
  651.     "L": ("L", 1, 1, (8,), None),
  652.     "LA": ("LA", 1, 1, (8,8), 2),
  653.     "P": ("P", 3, 1, (8,), None),
  654.     "PA": ("PA", 3, 1, (8,8), 2),
  655.     "I": ("I;32S", 1, 2, (32,), None),
  656.     "I;16": ("I;16", 1, 1, (16,), None),
  657.     "I;16S": ("I;16S", 1, 2, (16,), None),
  658.     "F": ("F;32F", 1, 3, (32,), None),
  659.     "RGB": ("RGB", 2, 1, (8,8,8), None),
  660.     "RGBX": ("RGBX", 2, 1, (8,8,8,8), 0),
  661.     "RGBA": ("RGBA", 2, 1, (8,8,8,8), 2),
  662.     "CMYK": ("CMYK", 5, 1, (8,8,8,8), None),
  663.     "YCbCr": ("YCbCr", 6, 1, (8,8,8), None),
  664.     "LAB": ("LAB", 8, 1, (8,8,8), None),
  665. }
  666.  
  667. def _cvt_res(value):
  668.     # convert value to TIFF rational number -- (numerator, denominator)
  669.     if type(value) in (type([]), type(())):
  670.         assert(len(value) % 2 == 0)
  671.         return value
  672.     if type(value) == type(1):
  673.         return (value, 1)
  674.     value = float(value)
  675.     return (int(value * 65536), 65536)
  676.  
  677. def _save(im, fp, filename):
  678.  
  679.     try:
  680.         rawmode, photo, format, bits, extra = SAVE_INFO[im.mode]
  681.     except KeyError:
  682.         raise IOError, "cannot write mode %s as TIFF" % im.mode
  683.  
  684.     ifd = ImageFileDirectory()
  685.  
  686.     # tiff header (write via IFD to get everything right)
  687.     fp.write(ifd.prefix + ifd.o16(42) + ifd.o32(8))
  688.  
  689.     ifd[IMAGEWIDTH] = im.size[0]
  690.     ifd[IMAGELENGTH] = im.size[1]
  691.  
  692.     # additions written by Greg Couch, gregc@cgl.ucsf.edu
  693.     # inspired by image-sig posting from Kevin Cazabon, kcazabon@home.com
  694.     if hasattr(im, 'tag'):
  695.         # preserve tags from original TIFF image file
  696.         for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION):
  697.             if im.tag.tagdata.has_key(key):
  698.                 ifd[key] = im.tag.tagdata.get(key)
  699.     if im.encoderinfo.has_key("description"):
  700.         ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"]
  701.     if im.encoderinfo.has_key("resolution"):
  702.         ifd[X_RESOLUTION] = ifd[Y_RESOLUTION] \
  703.                                 = _cvt_res(im.encoderinfo["resolution"])
  704.     if im.encoderinfo.has_key("x resolution"):
  705.         ifd[X_RESOLUTION] = _cvt_res(im.encoderinfo["x resolution"])
  706.     if im.encoderinfo.has_key("y resolution"):
  707.         ifd[Y_RESOLUTION] = _cvt_res(im.encoderinfo["y resolution"])
  708.     if im.encoderinfo.has_key("resolution unit"):
  709.         unit = im.encoderinfo["resolution unit"]
  710.         if unit == "inch":
  711.             ifd[RESOLUTION_UNIT] = 2
  712.         elif unit == "cm" or unit == "centimeter":
  713.             ifd[RESOLUTION_UNIT] = 3
  714.         else:
  715.             ifd[RESOLUTION_UNIT] = 1
  716.     if im.encoderinfo.has_key("software"):
  717.         ifd[SOFTWARE] = im.encoderinfo["software"]
  718.     if im.encoderinfo.has_key("date time"):
  719.         ifd[DATE_TIME] = im.encoderinfo["date time"]
  720.     if im.encoderinfo.has_key("artist"):
  721.         ifd[ARTIST] = im.encoderinfo["artist"]
  722.     if im.encoderinfo.has_key("copyright"):
  723.         ifd[COPYRIGHT] = im.encoderinfo["copyright"]
  724.  
  725.     dpi = im.encoderinfo.get("dpi")
  726.     if dpi:
  727.         ifd[RESOLUTION_UNIT] = 2
  728.         ifd[X_RESOLUTION] = _cvt_res(dpi[0])
  729.         ifd[Y_RESOLUTION] = _cvt_res(dpi[1])
  730.  
  731.     if bits != (1,):
  732.         ifd[BITSPERSAMPLE] = bits
  733.         if len(bits) != 1:
  734.             ifd[SAMPLESPERPIXEL] = len(bits)
  735.     if extra is not None:
  736.         ifd[EXTRASAMPLES] = extra
  737.     if format != 1:
  738.         ifd[SAMPLEFORMAT] = format
  739.  
  740.     ifd[PHOTOMETRIC_INTERPRETATION] = photo
  741.  
  742.     if im.mode == "P":
  743.         lut = im.im.getpalette("RGB", "RGB;L")
  744.         ifd[COLORMAP] = tuple(map(lambda v: ord(v) * 256, lut))
  745.  
  746.     # data orientation
  747.     stride = len(bits) * ((im.size[0]*bits[0]+7)/8)
  748.     ifd[ROWSPERSTRIP] = im.size[1]
  749.     ifd[STRIPBYTECOUNTS] = stride * im.size[1]
  750.     ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
  751.     ifd[COMPRESSION] = 1 # no compression
  752.  
  753.     offset = ifd.save(fp)
  754.  
  755.     ImageFile._save(im, fp, [
  756.         ("raw", (0,0)+im.size, offset, (rawmode, stride, 1))
  757.         ])
  758.  
  759. #
  760. # --------------------------------------------------------------------
  761. # Register
  762.  
  763. Image.register_open("TIFF", TiffImageFile, _accept)
  764. Image.register_save("TIFF", _save)
  765.  
  766. Image.register_extension("TIFF", ".tif")
  767. Image.register_extension("TIFF", ".tiff")
  768.  
  769. Image.register_mime("TIFF", "image/tiff")
  770.